package com.brush.app.service.impl;

import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.brush.app.domain.AppCourse;
import com.brush.app.domain.AppSubject;
import com.brush.app.domain.req.Course.add.AppCourseReq;
import com.brush.app.domain.req.Course.edit.AppCourseEditReq;
import com.brush.app.domain.resp.Subject.AppSubjectTreeResp;
import com.brush.app.domain.resp.course.AppCourseResp;
import com.brush.app.domain.resp.course.AppCourseTreeResp;
import com.brush.app.service.AppCourseService;
import com.brush.app.mapper.AppCourseMapper;
import com.brush.app.service.AppSubjectService;
import com.brush.common.exception.database.PrimaryKeyException;
import com.brush.common.exception.database.RecordNotFoundException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【app_course(课程树型表)】的数据库操作Service实现
 * @createDate 2024-10-31 16:44:54
 */
@Service
public class AppCourseServiceImpl extends ServiceImpl<AppCourseMapper, AppCourse>
        implements AppCourseService {

    //学科
    @Autowired
    private AppSubjectService appSubjectService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<AppCourseTreeResp> allCourseTree() {
        return null;
    }


    @Override
    public List<AppCourseTreeResp> searchTableTree(Long subjectId) {
        List<AppCourseTreeResp> appCourseTreeRespList = new ArrayList<>();
        LambdaQueryWrapper<AppCourse> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppCourse::getSubjectId, subjectId); // 添加根据subjectId过滤的条件
        queryWrapper.orderByAsc(AppCourse::getOrderNum);
        //查询属于特定subjectId的course
        List<AppCourse> appCourseList = this.baseMapper.selectList(queryWrapper);
        //遍历parentid=0的数据
        appCourseList.stream().filter(p -> p.getParentId().intValue() == 0).forEach(item -> {
            AppCourseTreeResp root = new AppCourseTreeResp();
            root.setId(item.getId());
            root.setSubjectId(item.getSubjectId());
            root.setAncestors(item.getAncestors());
            root.setName(item.getName());
            root.setRemark(item.getRemark());
            root.setTotal(item.getTotal());
            root.setOrderNum(item.getOrderNum());
            root.setStatus(item.getStatus());

            //如果有子节点就递归构建子节点
            buildChildrenTree(root, appCourseList); // 确保递归方法接收所有课程的列表
            appCourseTreeRespList.add(root);
        });
        return appCourseTreeRespList;
    }

    @Override
    public boolean add(AppCourseReq req) {
        //验证名称是否重复
        if (this.baseMapper.exists(new LambdaQueryWrapper<AppCourse>().eq(AppCourse::getName, req.getName()))) {
            throw new ServiceException("名称重复");
        }
        //得到父部门的ancestors信息
        String ancestors ="0";
        if(req.getParentId()!=null){
           ancestors+=","+req.getParentId();
        }

        AppCourse newEntity = new AppCourse();
        //拷贝
        BeanUtils.copyProperties(req, newEntity);

        newEntity.setAncestors(ancestors + "," + req.getParentId());
        return this.save(newEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean edit(AppCourseEditReq req) {

        AppCourse appCourse = this.getById(req.getId());
        if (Objects.isNull(appCourse)) {
            throw new RecordNotFoundException();
        }
        appCourse.setName(req.getName());
        appCourse.setRemark(req.getRemark());
        appCourse.setOrderNum(req.getOrderNum());
        appCourse.setStatus(req.getStatus());

        return this.updateById(appCourse);

    }

    @Override
    public AppCourseResp findById(Long id) {
        if (Objects.isNull(id)) {
            throw new PrimaryKeyException();
        }
        AppCourseResp appCourse = this.baseMapper.findById(id);
        return appCourse;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteById(Long[] ids) {
        final AppCourseServiceImpl appCourseService = this;
        if (Objects.isNull(ids) || ids.length == 0) {
            throw new PrimaryKeyException();
        }
        this.redisTemplate.execute(new SessionCallback<Void>() {
            @Override
            public Void execute(RedisOperations operations) throws DataAccessException {
                // 开启redis事务
                operations.multi();

                // 循环删除，因为数据量不大, 时间复杂度O(n), 事务问题
                try {
                    for (Long id : ids) {
                        AppCourse db = appCourseService.getById(id);
                        if (Objects.nonNull(db)) {
                            //删除数据库中的值
                            appCourseService.removeById(id);
                            //移出缓存中的值
                            String redisKey = " "+db.getId();
                            operations.delete(redisKey);
                        }
                    }
                    // 提交redis事务
                    operations.exec();

                } catch (Exception e) {
                    operations.discard();
                    throw e;
                }
                return null;
            }
        });
        return true;
    }


    // 递归构建子节点的方法
    private void buildChildrenTree(AppCourseTreeResp root, List<AppCourse> appCourseList) {
        List<AppCourseTreeResp> children = appCourseList.stream()
                .filter(course -> course.getParentId().equals(root.getId()))
                .map(course -> {
                    AppCourseTreeResp child = new AppCourseTreeResp();
                    child.setId(course.getId());
                    child.setSubjectId(course.getSubjectId());
                    child.setAncestors(course.getAncestors());
                    child.setName(course.getName());
                    child.setRemark(course.getRemark());
                    child.setTotal(course.getTotal());
                    child.setOrderNum(course.getOrderNum());
                    child.setStatus(course.getStatus());
                    // 递归调用以构建更深层次的子节点
                    buildChildrenTree(child, appCourseList);
                    return child;
                })
                .collect(Collectors.toList());
        if(!children.isEmpty()){
            root.setChildren(children);
        }

    }





    private List<AppCourseTreeResp> buildTree(List<AppCourse> appCourseList) {
        List<AppCourseTreeResp> appCourseTreeRespList = new ArrayList<>();
        //查询根节点
        appCourseList.stream().filter(p -> p.getParentId().intValue() == 0).forEach(item -> {
            AppCourseTreeResp root = new AppCourseTreeResp();
            root.setId(item.getId());
            root.setName(item.getName());
            //递归构建子节点
            // buildChildrenTree(root,appCourseList);
            appCourseTreeRespList.add(root);
        });
        return appCourseTreeRespList;
    }


    /**
     * 构建学科以及课程树
     * @return
     */
    @Override
    public List<AppCourseTreeResp> buildSubjectTree() {
       List<AppSubject> allSubject = this.appSubjectService.list();


        List<AppCourseTreeResp> allCourseTreeResp = new ArrayList<>();

       allSubject.forEach(item->{
           //先构建学科课程
           AppCourseTreeResp root = new AppCourseTreeResp();
           root.setId(item.getId());
           root.setName(item.getName());
           root.setSubjectId(-1L);

           //构建学科下的课程
           List<AppCourse> dbList = this.list();
           List<AppCourseTreeResp> childrenList =  dbList.stream()
                   .filter(p -> p.getSubjectId().intValue() == item.getId().intValue() && p.getParentId().equals(0L))
                   .map(AppCourseTreeResp::new).collect(Collectors.toList());
           if(!childrenList.isEmpty()){
               //遍历子节点
               childrenList.forEach(child->{

                   //遍历子节点
                   List<AppCourseTreeResp> children = dbList.stream()
                           .filter(p -> p.getParentId().equals(child.getId()))
                           .map(AppCourseTreeResp::new).collect(Collectors.toList());
                   if(!children.isEmpty()){
                       child.setChildren(children);
                   }


               });
               root.setChildren(childrenList);
           }

           allCourseTreeResp.add(root);
       });

        return allCourseTreeResp;
    }

    /**
     * 根据课程id获取课程名称
     * @param courseId
     * @return
     */
    @Override
    public String getNameById(Long courseId) {
        AppCourse appCourse = this.getById(courseId);
        if(appCourse.getAncestors().equals("0")){
            return appCourse.getName();
        }else{
           String parentId= appCourse.getAncestors().split(",")[1];
           AppCourse parent=this.getById(Long.parseLong(parentId));
           return parent.getName()+"/"+appCourse.getName();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateQuestionNum(Long courseId, int num) {
        AppCourse appCourse = this.getById(courseId);
        appCourse.setTotal(appCourse.getTotal()+num);
        this.updateById(appCourse);

        //再更新上级的总数量
       String parentId= appCourse.getAncestors().split(",")[1];
       AppCourse parent=this.getById(Long.parseLong(parentId));
       parent.setTotal(parent.getTotal()+num);
       this.updateById(parent);
       return true;
    }

    /**
     * 获取课程的父级id
     * @param courseId
     * @return
     */
    @Override
    public Long[] getParentsId(Long courseId) {
        List<Long> list=new ArrayList<>();

        AppCourse appCourse = this.getById(courseId);

        list.add(appCourse.getSubjectId());
        list.add(appCourse.getParentId());
        list.add(appCourse.getId());
        return list.toArray(new Long[0]);
    }


}




